
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <signal.h>
#include <time.h>
#include <sys/types.h>
#include <pthread.h>
#include <stdarg.h>
#include <sys/time.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "core.h"
#include "utils_ptrlist.h"
#include "utils_net.h"
#include "ts_thread.h"
#include "protocol.h"
#include "utils_sys.h"
#include "tcpproxy.h"

#define max(a, b) (((a) > (b)) ? (a) : (b))

typedef struct tagForwardService
{
    int index;
    int bQuit;
    char client_id[64];
    int port_client; // 客户端要连接的端
    int port_device; // 设备端要联机的端
    int fd_client;
    int fd_device;
    int peer_client;
    int peer_device;
    int64_t ltLastChat;
    pthread_t thread;
    CientInfo client_info;
} ForwardService;

static PtrList ForwardList = PTRLIST_INITIALIZER;
static pthread_mutex_t ForwardListLock = PTHREAD_MUTEX_INITIALIZER;
#define Lock() pthread_mutex_lock(&ForwardListLock)
#define Unlock() pthread_mutex_unlock(&ForwardListLock)

#define trace_log printf

static void *service_work(void *arg)
{
    int64_t ltLastConnected = 0;
    int count_connect = 0;
    ForwardService *obj = (ForwardService *)arg;
    pthread_detach(pthread_self());
    int64_t ltConnected = 0;
    obj->ltLastChat = get_sys_tick64();
    fd_set fs;
    char buffer[4096] = {0};
    int n = 0;
    int max_fd;
    struct timeval tv;
    while (!obj->bQuit)
    {
        if (obj->peer_client > 0 && obj->peer_device > 0)
        {
            // 创建转发路径..
            ProxyAddClient(obj->peer_client, obj->peer_device);
            obj->peer_client = -1;
            obj->peer_device = -1;
        }
        if (ltConnected != 0 && obj->peer_device <= 0 && get_sys_tick64() > ltConnected + 5000)
        {
            ltConnected = 0;
            OnDeviceConnceted(&obj->client_info, 400, "设备端超时未连接");
            sock_close(obj->peer_client);
            obj->peer_client = -1;
        }
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        FD_ZERO(&fs);
        FD_SET(obj->fd_client, &fs);
        FD_SET(obj->fd_device, &fs);
        max_fd = max(obj->fd_client, obj->fd_device);
        int nsel = select(max_fd + 1, &fs, NULL, NULL, &tv);
        if (nsel > 0)
        {
            if (FD_ISSET(obj->fd_client, &fs))
            {
                if (obj->peer_client <= 0)
                {
                    obj->peer_client = sock_accept(obj->fd_client);
                    if (obj->peer_client <= 0)
                    {
                        trace_log("new client is comming, [client_pc] accept failed!\r\n");
                        continue;
                    }
                    trace_log("new client is comming, from client_pc , port:%d  \r\n", obj->port_client);
                    ltConnected = get_sys_tick64();
                    OnClientConnceted(&obj->client_info);
                    continue;
                }
                else
                {
                    // 只有当前一个链接主动断开了才能继续接收下一个连接，不存在顶替的功能，不然并发的请求会出问题
                }
            }
            if (FD_ISSET(obj->fd_device, &fs))
            {
                if (obj->peer_client > 0)
                {
                    obj->peer_device = sock_accept(obj->fd_device);
                    ltConnected = 0;
                    OnDeviceConnceted(&obj->client_info, 0, "架线成功");
                    trace_log("new client is comming, from device , port:%d ! \r\n", obj->port_device);
                    continue;
                }
                else
                {
                    obj->peer_device = sock_accept(obj->fd_device);
                    if (obj->peer_device > 0)
                    {
                        trace_log("unknown pair tcp client connection..\r\n");
                        sock_close(obj->peer_device);
                    }
                }
            }
        }
    }
    trace_log("Thread BQuit:%d\r\n", obj->bQuit);
    if (obj->fd_client > 0)
        sock_close(obj->fd_client);
    obj->fd_client = -1;
    if (obj->fd_device > 0)
        sock_close(obj->fd_device);
    obj->fd_device = -1;
    trace_log("forward thread exit..\r\n");
    return NULL;
}

int GetForwardServiceCount()
{
    return ForwardList.count;
}

const int FindForwardClientId(const char *deviceId, char *client_id)
{
    int find = 0;
    POSITION pos = NULL;
    Lock();
    for (pos = ForwardList.head; pos != NULL; pos = pos->next)
    {
        ForwardService *obj = (ForwardService *)pos->ptr;
        if (strcmp(obj->client_info.device_id, deviceId) == 0)
        {
            strcpy(client_id, obj->client_info.device_id);
            find = 1;
            break;
        }
    }
    Unlock();
    return find;
}

void CreateForwardObject(CientInfo *info, const char *client_id, int port_client, int port_device, int fd_client, int fd_device)
{
    ForwardService *obj = malloc(sizeof(ForwardService));
    memset(obj, 0, sizeof(ForwardService));
    memcpy(&obj->client_info, info, sizeof(CientInfo));
    strcpy(obj->client_id, client_id);
    obj->port_client = port_client;
    obj->port_device = port_device;
    printf("port_client:%d, port_device:%d\r\n", port_client, port_device);
    obj->fd_client = fd_client;
    obj->fd_device = fd_device;
    pthread_create(&obj->thread, NULL, service_work, obj);
    Lock();
    PtrList_append(&ForwardList, obj);
    Unlock();
}

void DesctoryAllObject()
{
    Lock();
    POSITION pos = ForwardList.head;
    while (pos != NULL)
    {
        ForwardService *obj = (ForwardService *)pos->ptr;
        obj->bQuit = 1;
        obj = PtrList_remove(&ForwardList, pos);
        pthread_join(obj->thread, NULL);
        if (obj->fd_client > 0)
            sock_close(obj->fd_client);
        trace_log("close fd_client:%d\r\n", obj->fd_client);
        if (obj->fd_device > 0)
            sock_close(obj->fd_device);
        trace_log("close fd_device:%d\r\n", obj->fd_device);
        obj->fd_client = obj->fd_device = -1;
        printf("free object [%s]\r\n", obj->client_id);
        free(obj);
        pos = ForwardList.head;
    }
    Unlock();
}

void DesctoryObject(const char *client_id)
{
    Lock();
    POSITION pos = ForwardList.head;
    while (pos != NULL)
    {
        ForwardService *obj = (ForwardService *)pos->ptr;
        if (strcmp(obj->client_id, client_id) == 0)
        {
            obj->bQuit = 1;
            obj = PtrList_remove(&ForwardList, pos);
            pthread_join(obj->thread, NULL);
            if (obj->fd_client > 0)
                sock_close(obj->fd_client);
            trace_log("close fd_client:%d\r\n", obj->fd_client);
            if (obj->fd_device > 0)
                sock_close(obj->fd_device);
            trace_log("close fd_device:%d\r\n", obj->fd_device);
            printf("free object [%s]\r\n", client_id);
            free(obj);
            pos = ForwardList.head;
            continue;
        }
        pos = pos->next;
    }
    Unlock();
}

const char *GetForwardServiceId(int index)
{
    POSITION pos = ForwardList.head;
    index = index <= 0 ? 0 : index;
    while (pos != NULL)
    {
        ForwardService *obj = (ForwardService *)pos->ptr;
        if (index-- == 0)
            return obj->client_id;
        pos = pos->next;
    }
    return NULL;
}
